package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

import ch.qos.logback.core.net.server.Client;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.ServiceCapability;
import com.huaweicloud.sdk.iotda.v5.model.ShowProductRequest;
import com.huaweicloud.sdk.iotda.v5.model.ShowProductResponse;
import com.zzyl.common.constant.Constants;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.nursing.config.WebSocketServer;
import com.zzyl.nursing.domain.AlertData;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.job.AmqpClient;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IAlertDataService;
import com.zzyl.nursing.vo.AlertNotifyVo;
import com.zzyl.system.mapper.SysUserMapper;
import com.zzyl.system.mapper.SysUserRoleMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.el.parser.AstLessThan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.AlertRuleMapper;
import com.zzyl.nursing.domain.AlertRule;
import com.zzyl.nursing.service.IAlertRuleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.util.CollectionUtils;
import org.springframework.util.NumberUtils;

import javax.swing.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 报警规则Service业务层处理
 *
 * @author Jiagege
 * @date 2025-08-04
 */
@Service
@Slf4j
public class AlertRuleServiceImpl extends ServiceImpl<AlertRuleMapper, AlertRule> implements IAlertRuleService {
    @Autowired
    private AlertRuleMapper alertRuleMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private IAlertDataService alertDataService;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 查询报警规则
     *
     * @param id 报警规则主键
     * @return 报警规则
     */
    @Override
    public AlertRule selectAlertRuleById(Long id) {
        return getById(id);
    }

    /**
     * 查询报警规则列表
     *
     * @param alertRule 报警规则
     * @return 报警规则
     */
    @Override
    public List<AlertRule> selectAlertRuleList(AlertRule alertRule) {
        return alertRuleMapper.selectAlertRuleList(alertRule);
    }

    /**
     * 新增报警规则
     *
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int insertAlertRule(AlertRule alertRule) {
        return save(alertRule) ? 1 : 0;
    }

    /**
     * 修改报警规则
     *
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int updateAlertRule(AlertRule alertRule) {
        return updateById(alertRule) ? 1 : 0;
    }

    /**
     * 批量删除报警规则
     *
     * @param ids 需要删除的报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleByIds(Long[] ids) {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除报警规则信息
     *
     * @param id 报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleById(Long id) {
        return removeById(id) ? 1 : 0;
    }

    /**
     * 过滤设备上报数据
     */
    @Override
    public void alertFilter() {

        //查询所有规则
        List<AlertRule> alertRuleList = this.list(Wrappers.<AlertRule>lambdaQuery().eq(AlertRule::getStatus, 1));
        if (CollUtil.isEmpty(alertRuleList)) {
            log.info("未查询到报警规则,返回");
            return;
        }
        //查询所有设备上报数据
        List deviceDataListStr = redisTemplate.opsForHash().values(Constants.IOT_DEVICE_LAST_DATA);
        if (CollectionUtils.isEmpty(deviceDataListStr)) {
            log.info("未查询到任何设备的上报数据,返回");
            return;
        }
        //解析上报数据------
        List<DeviceData> deviceDataList = new ArrayList<>();
        //遍历所有设备上报数据
        deviceDataListStr.forEach(deviceData -> {
            List<DeviceData> dataList = JSONUtil.toList(deviceData.toString(), DeviceData.class);
            deviceDataList.addAll(dataList);
        });

        //数据报警处理器
        deviceDataList.forEach(deviceData -> {
            alertFilter(deviceData);
        });
    }

    /**
     * 上报数据过滤---方法的重载,区别与上面不带参数,这里添加参数尽心进一步过滤
     *
     * @param deviceData
     */
    private void alertFilter(DeviceData deviceData) {
        //遍历所有规则---启用状态   todo这里直接遍历所有规则,包含产品物模型下该设备独有的规则,所以直接查所有设备的规则???
        List<AlertRule> ruleList = this.list(Wrappers.<AlertRule>lambdaQuery().eq(AlertRule::getStatus, 1));
        if (CollUtil.isEmpty(ruleList)) {
            log.info("未查询到任何的规则,返回");
            return;
        }

        //2.查询该产品物模型下的全部设备的规则
        List<AlertRule> alertRuleList = this.list(
                Wrappers.<AlertRule>lambdaQuery()
                        .eq(AlertRule::getProductKey, deviceData.getProductKey())//产品
                        .eq(AlertRule::getFunctionId, deviceData.getFunctionId())//物模型/属性id
                        .eq(AlertRule::getStatus, 1)//启用状态
        );
        if (CollectionUtil.isEmpty(alertRuleList)) {
            log.info("未查询到该产品下对应的规则,返回");
            return;
        }
        //3.遍历每一条规则，并进行校验
        alertRuleList.forEach(alertRule -> {
            deviceDataAlarmHandle(alertRule, deviceData);
        });

    }

    private void deviceDataAlarmHandle(AlertRule alertRule, DeviceData deviceData) {
        //判断是否在生效时间内 00:00:00-23:59:00     由于全天报警,这里其实也可以省略是否生效,因为必然生效
        String[] timeArrange = alertRule.getAlertEffectivePeriod().split("~");
        LocalTime startTime = LocalTime.parse(timeArrange[0]);
        LocalTime endTime = LocalTime.parse(timeArrange[1]);
        LocalTime alertTime = deviceData.getAlarmTime().toLocalTime();
        if (alertTime.isBefore(startTime) || alertTime.isAfter(endTime)) {
            log.info("非生效时间段报警,不予处理,返回");
            return;
        }
        String iotId = deviceData.getIotId();
        //检验数据是否达到阈值
        //设置报警数量的key
        String alertCountKey = Constants.ALERT_TRIGGER_COUNT_PREFIX + iotId + ":" + deviceData.getFunctionId() + ":" + alertRule.getId();

        //获取规则中的数据阈值和预算符
        //数据阈值
        Long value = alertRule.getValue();
        //运算符
        String operator = alertRule.getOperator();

        // 数据对比，上报的数据与规则中的阈值进行对比，规则中的，>=65或者<65 ,上报数据dataValue
        Long dataValue = Long.valueOf(deviceData.getDataValue());
        int compare = NumberUtil.compare(dataValue, value);
        //两个参数x,y(参数有顺序要求，左边是上报的数据，后边是规则的数据)  x==y 返回0  x>y 返回大于0  x<y 返回小于0的数值
        if ((compare >= 0 && operator.equals(">=")) || (compare < 0 && operator.equals("<"))) {
            //异常数据继续往下走
            log.info("当前数据报警异常,继续");
        } else {
            //正常数据，并删除redis报警数，然后直接返回
            log.info("当前数据不符合报警异常,删除redis报警数");
            //删除redis报警数
            redisTemplate.delete(alertCountKey);
            return;
        }


        //判断是否在沉默周期内
        String silentKey = Constants.ALERT_SILENT_PREFIX + iotId + ":" + deviceData.getFunctionId() + ":" + alertRule.getId();
        String silentData = (String) redisTemplate.opsForValue().get(silentKey);
//        String silentData = String.valueOf(redisTemplate.opsForValue().get(silentKey));
        if (ObjectUtils.isNotEmpty(silentData)) {
            //为空,继续;不为空,返回
            //为空,即沉默周期内无报警数;不为空,即非沉默周期,因此有报警数据
            log.info("当前数据不为空,即非沉默周期,返回");
            return;
        }
        //为空的情况,开始查询报警次数
//        String alertCountData = String.valueOf( redisTemplate.opsForValue().get(alertCountKey));
        String alertCountData = (String) redisTemplate.opsForValue().get(alertCountKey);
        //次数为空,设置次数为1;次数有值,设置次数+1     !!!与具体值无关,这里只考虑对应的次数
        int count = StringUtils.isEmpty(alertCountData) ? 1 : (Integer.parseInt(alertCountData) + 1);
        //若当前报警次数≠规则内的报警周期,表明报警次数还在增加,只有相等,才触发报警
        if (ObjectUtil.notEqual((alertRule.getDuration()), count)) {
            redisTemplate.opsForValue().set(alertCountKey, String.valueOf(count));
        }
        //相等的情况,删除报警次数,清零
        redisTemplate.delete(alertCountKey);

        //校验通过,添加沉默周期     !!!与具体值无关,这里只考虑对应的次数,所以这里的1,无实际意义
        redisTemplate.opsForValue().set(silentKey, "1", alertRule.getAlertSilentPeriod(), TimeUnit.MINUTES);

        //查询待通知人员
        // 报警数据类型
        List<Long> userIds = new ArrayList<>();
        if (alertRule.getAlertDataType().equals(0)) {//---老人异常数据
            //位置类型
            if (deviceData.getLocationType().equals(0)) {//绑定老人   手表
                userIds = deviceMapper.selectNursingIdsByIotIdWithElder(iotId);
            } else if (deviceData.getLocationType().equals(1)) {//绑定床位  睡眠监测带
                userIds = deviceMapper.selectNursingIdsByIotIdWithBed(iotId);
            }

        } else {//---设备异常数据    通知维修人员
            userIds = sysUserRoleMapper.selectUserIdByRoleName("维修工");
        }
        List<Long> manageIds = sysUserRoleMapper.selectUserIdByRoleName("超级管理员");
        //合并所有人
        Collection<Long> allUserIds = CollUtil.addAll(userIds, manageIds);
        //去重
        allUserIds = CollUtil.distinct(allUserIds);

        //5.4 保存报警数据
        List<AlertData> alertDataList = insertAlertData(allUserIds, alertRule, deviceData);
        // websocket推送消息
        websocketNotity(alertDataList.get(0), alertRule,allUserIds);

    }

    private void websocketNotity(AlertData alertData, AlertRule alertRule, Collection<Long> allUserIds) {
        // 属性拷贝
        AlertNotifyVo alertNotifyVo = BeanUtil.toBean(alertData, AlertNotifyVo.class);
        alertNotifyVo.setFunctionName(alertRule.getFunctionName());
        alertNotifyVo.setAlertDataType(alertRule.getAlertDataType());
        alertNotifyVo.setNotifyType(1);
        // 向指定的人推送消息
        webSocketServer.sendMessageToConsumer(alertNotifyVo, allUserIds);
    }

    private List<AlertData>  insertAlertData(Collection<Long> allUserIds, AlertRule alertRule, DeviceData deviceData) {
        // 对象拷贝
        AlertData alertData = BeanUtil.toBean(deviceData, AlertData.class);
        alertData.setAlertRuleId(alertRule.getId());
        // 心率<60,持续3个周期就报警
        String alertReason = CharSequenceUtil.format("{}{}{},持续{}个周期就报警", alertRule.getFunctionName(), alertRule.getOperator(), alertRule.getValue(), alertRule.getDuration());
        alertData.setAlertReason(alertReason);
        alertData.setStatus(0);
        alertData.setType(alertRule.getAlertDataType());
        // 遍历allUserIds
        List<AlertData> list = allUserIds.stream().map(userId -> {
            AlertData dbAlertData = BeanUtil.toBean(alertData, AlertData.class);
            dbAlertData.setUserId(userId);
            dbAlertData.setCreateTime(null);
            dbAlertData.setId(null);
            return dbAlertData;
        }).collect(Collectors.toList());

        // 批量保存
        alertDataService.saveBatch(list);
        return list;
    }


}

